PoC/iOS/Bluetooth Tracing PoC/Sources/Services/CentralService.swift (91 lines of code) (raw):

// ========================================================================= // Copyright 2020 EPAM Systems, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ========================================================================= import UIKit import CoreBluetooth /* Service that works as a central, scans for peripherals with the predefined identifier, discovers service's characteristic with the predefined identifier, reads a value (user identifier), logs it and displays it as a local notification Message for keys 'Privacy - Bluetooth Always Usage Description' should be added to Info.plist Background mode 'Uses Bluetooth LE accessories' should be enable in the Capabilities of the project */ class CentralService: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate { private var centralManager: CBCentralManager! private var discoveredPeripherals = Set<CBPeripheral>() private var connectedPeripherals = Set<CBPeripheral>() @PredefinedIdentifier(.service) private var serviceIdentifier: String @PredefinedIdentifier(.characteristic) private var characteristicIdentifier: String override init() { super.init() centralManager = CBCentralManager(delegate: self, queue: .main) NotificationCenter.default.addObserver(forName: .RestartBluetooth, object: nil, queue: nil) { _ in self.stopScan() self.startScan() } } private func startScan() { let services = [serviceIdentifier.cbuuid] let options: [String: Any] = [CBCentralManagerScanOptionAllowDuplicatesKey: NSNumber(value: true), CBCentralManagerScanOptionSolicitedServiceUUIDsKey: services] centralManager.scanForPeripherals(withServices: services, options: options) Logger.shared.logMessage("CM did start scan\n") } private func stopScan() { centralManager.stopScan() Logger.shared.logMessage("CM did stop scan\n") } // MARK: - CBCentralManagerDelegate func centralManagerDidUpdateState(_ central: CBCentralManager) { switch central.state { case .poweredOn: Logger.shared.logMessage("CM scan for peripherals with service \(serviceIdentifier)\n") startScan() default: Logger.shared.logMessage("CM stop scan\n") stopScan() } } func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { Logger.shared.logMessage("CM did discover peripheral \(peripheral.identifier)\n") discoveredPeripherals.insert(peripheral) central.connect(peripheral, options: nil) } func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { Logger.shared.logMessage("CM did connect peripheral \(peripheral.identifier)\n") discoveredPeripherals.remove(peripheral) connectedPeripherals.insert(peripheral) peripheral.delegate = self peripheral.discoverServices([serviceIdentifier.cbuuid]) } func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { Logger.shared.logMessage("CM did fail to discover peripheral \(peripheral.identifier)\n") discoveredPeripherals.remove(peripheral) } func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { Logger.shared.logMessage("CM did disconnect peripheral \(peripheral.identifier)\n") connectedPeripherals.remove(peripheral) } // MARK: - CBPeripheralDelegate func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { guard error == nil, let service = peripheral.services?.first else { Logger.shared.logMessage("P \(peripheral.identifier) did discover services\n") centralManager.cancelPeripheralConnection(peripheral) return } peripheral.discoverCharacteristics([characteristicIdentifier.cbuuid], for: service) } func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { guard error == nil, let characteristic = service.characteristics?.first else { Logger.shared.logMessage("P \(peripheral.identifier) did discover characteristics\n") centralManager.cancelPeripheralConnection(peripheral) return } peripheral.readValue(for: characteristic) } func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { defer { centralManager.cancelPeripheralConnection(peripheral) } guard error == nil, let data = characteristic.value, let value = String(data: data, encoding: .utf8) else { Logger.shared.logMessage("P \(peripheral.identifier) did update value\n") return } var message = "Identifier -> \(value)\n" message += "Date -> \(Date.now.format())\n" message += "My battery status -> \(UIDevice.current.batteryStatus)\n" Logger.shared.logMessage(message) NotificationService.shared.show(message: "Found another device: \(value)") } }